package my.framework.ssm.sample.config;

import my.framework.ssm.sample.common.mq.redis.RedisMqListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;

/**
 * @author NuKi
 * @date 2018/11/26 22:37
 */
@Configuration
@ComponentScan("my.framework.ssm.sample.common.mq.redis")
public class RedisConfig {
    private final Environment env;

    public RedisConfig(Environment env) {
        this.env = env;
    }

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
        redisConfig.setHostName(env.getProperty("redis.host", "localhost"));
        redisConfig.setPort(env.getProperty("redis.port", Integer.class, 6379));
        redisConfig.setDatabase(env.getProperty("redis.db", Integer.class, 0));
        redisConfig.setPassword(env.getProperty("redis.password"));

        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //最大分配的对象数
        jedisPoolConfig.setMaxTotal(1024);
        //最大能够保持idel状态的对象数
        jedisPoolConfig.setMaxIdle(200);
        //当池内没有返回对象时，最大等待时间
        jedisPoolConfig.setMaxWaitMillis(1000);
        //当调用borrow Object方法时，是否进行有效性检查
        jedisPoolConfig.setTestOnBorrow(true);
        //当调用return Object方法时，是否进行有效性检查
        jedisPoolConfig.setTestOnReturn(true);

        JedisClientConfiguration jedisConfig = JedisClientConfiguration
                .builder().usePooling().poolConfig(jedisPoolConfig)
                .build();

        return new JedisConnectionFactory(redisConfig, jedisConfig);
    }

    @Bean
    public <K, E> RedisTemplate<K, E> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<K, E> redisTemplate = new RedisTemplate<>();

        JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();
        GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
        redisTemplate.setKeySerializer(jdkSerializer);
        redisTemplate.setValueSerializer(jsonSerializer);

        redisTemplate.setHashKeySerializer(jdkSerializer);
        redisTemplate.setHashValueSerializer(jsonSerializer);

        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate redisTemplate = new StringRedisTemplate(redisConnectionFactory);
        GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
        redisTemplate.setValueSerializer(jsonSerializer);
        redisTemplate.setHashKeySerializer(jsonSerializer);
        return redisTemplate;
    }

    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(RedisCacheConfiguration
                        .defaultCacheConfig()
                        .prefixKeysWith("sample")
                        .entryTtl(Duration.of(10, ChronoUnit.MINUTES)))
                .withInitialCacheConfigurations(new HashMap<String, RedisCacheConfiguration>(6) {{
                    put("halfHour", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.of(30, ChronoUnit.MINUTES)));
                    put("hour", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.of(1, ChronoUnit.HOURS)));
                    put("oneDay", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.of(1, ChronoUnit.DAYS)));
                    //shiro cache keys
                    put("authorizationCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.of(30, ChronoUnit.MINUTES)));
                    put("authenticationCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.of(30, ChronoUnit.MINUTES)));
                    put("activeSessionCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.of(30, ChronoUnit.MINUTES)));
                }})
                .build();
    }

    /**
     * @return
     */
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory,
                                                                       RedisMqListener redisMqListener) {

        RedisMessageListenerContainer container = new RedisMessageListenerContainer();

        container.setConnectionFactory(redisConnectionFactory);
        /*//可以实现重试机制
        container.setErrorHandler();*/
        /**
         * 添加订阅者监听类，数量不限.PatternTopic定义监听主题
         */
        container.addMessageListener(redisMqListener, RedisMqListener.getTopicList());
        return container;
    }

}
